package com.fine.hair.applet.controller;

import cn.hutool.core.bean.BeanUtil;
import cn.hutool.core.date.DateUtil;
import com.baomidou.mybatisplus.core.toolkit.CollectionUtils;
import com.fine.hair.applet.mapper.*;
import com.fine.hair.applet.service.BranchService;
import com.fine.hair.applet.service.EvaluateService;
import com.fine.hair.comm.exception.BusinessException;
import com.fine.hair.comm.model.*;
import com.fine.hair.comm.pojo.StaffSimpleInfo;
import com.fine.hair.comm.pojo.wx.WxAccessTokenResponse;
import com.fine.hair.comm.pojo.wx.config.WxMpProperty;
import com.fine.hair.comm.utils.*;
import cn.hutool.core.lang.Snowflake;
import cn.hutool.core.util.ObjectUtil;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.core.metadata.IPage;
import com.baomidou.mybatisplus.core.toolkit.Constants;
import com.fine.hair.comm.dto.*;
import com.fine.hair.comm.enums.OrderStatus;
import com.fine.hair.comm.enums.StatusType;
import com.fine.hair.comm.vo.OrderInfoVo;
import com.fine.hair.comm.vo.StaffEvaluateVo;
import com.fine.hair.comm.vo.StaffMienVo;
import com.fine.hair.comm.vo.StaffOrderVo;
import com.fine.hair.comm.wx.WxClient;
import com.google.common.collect.Lists;
import com.google.gson.Gson;
import io.swagger.annotations.Api;
import io.swagger.annotations.ApiOperation;
import lombok.extern.slf4j.Slf4j;
import org.gavaghan.geodesy.Ellipsoid;
import org.gavaghan.geodesy.GeodeticCalculator;
import org.gavaghan.geodesy.GeodeticCurve;
import org.gavaghan.geodesy.GlobalCoordinates;
import org.springframework.beans.BeanUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.http.HttpStatus;
import org.springframework.http.ResponseEntity;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.validation.annotation.Validated;
import org.springframework.web.bind.annotation.*;
import org.springframework.web.client.RestTemplate;

import javax.annotation.Resource;
import java.math.BigDecimal;
import java.text.MessageFormat;
import java.text.SimpleDateFormat;
import java.time.LocalDateTime;
import java.time.ZoneId;
import java.util.ArrayList;
import java.util.Date;
import java.util.List;
import java.util.Objects;

import static com.fine.hair.comm.wx.WxClient.URL_WX_LITE_ACCESS_TOKEN;

/**
 * <p>个人中心控制层</p>
 *
 * @author mouseyCat
 * @date 2020/10/4 14:55
 */
@Slf4j
@Api(tags = {"个人中心相关接口"})
@RestController
@RequestMapping("/personal-center/")
public class PersonalCenterController {

    @Resource
    private UserMapper userMapper;

    @Autowired
    private Snowflake snowflake;

    @Resource
    private EvaluateMapper evaluateMapper;
    @Resource
    private LeaveMapper leaveMapper;

    @Resource
    private OrderMapper orderMapper;

    @Resource
    private ConsumeMapper consumeMapper;

    @Resource
    private ItemMapper itemMapper;

    @Autowired
    private BranchService branchService;

    @Autowired
    private EvaluateService evaluateService;


    @ApiOperation("个人信息/个人中心/我的钱包")
    @GetMapping("personal-info/{userId}")
    public ApiResponse<User> personalInfo(@PathVariable Long userId) {
        return ApiResponse.ofSuccess(userMapper.selectById(userId));
    }

    @ApiOperation(value = "评价页面-提交评价", notes = "一颗心传 1，两颗心传 2，以此类推 | " +
            "目前我只接收 “综合满意” 与 “评论”")
    @PostMapping("submit-evaluate")
    public ApiResponse submitEvaluate(@RequestBody SubmitEvaluateDto dto) {
        Evaluate evaluate1 = evaluateMapper.selectOne(new LambdaQueryWrapper<Evaluate>().eq(Evaluate::getOrderId,
                dto.getOrderId()));
        if (ObjectUtil.isNotNull(evaluate1)) {
            throw new BusinessException("已经评价过该订单，不可重复评价");
        }
        Evaluate evaluate = new Evaluate();
        BeanUtils.copyProperties(dto, evaluate);
        evaluate.setScore(new BigDecimal(String.valueOf(dto.getScore())));
        evaluate.setId(snowflake.nextId());
        if (!CollectionUtils.isEmpty(dto.getLabel())) {
            String label = String.join(Constants.COMMA, dto.getLabel());
            evaluate.setLabel(label);
        }
        Order order = orderMapper.selectById(dto.getOrderId());
        evaluate.setEvaluateId(Long.valueOf(order.getUserId()));
        evaluate.setOrderId(dto.getOrderId());
        return evaluateMapper.insert(evaluate) == 1 ? ApiResponse.ofSuccess() : ApiResponse.ofStatus(MyStatus.ERROR);
    }

    @Transactional(rollbackFor = Exception.class)
    @ApiOperation("创建订单")
    @PostMapping("create-order")
    public ApiResponse createOrder(@Validated @RequestBody CreateOrderDto dto) {
        // 判断技师是否请假
        Date executeTime = DateUtil.parseDateTime(dto.getExecuteTime());
        if(executeTime.getTime()<System.currentTimeMillis()){
            return ApiResponse.ofFailed("此服务时间已过，请重新选择...");
        }
        User technician = userMapper.selectById(dto.getTechnicianId());
        // 如果下班
        if(technician.getOnWork().intValue()!=1){
            return ApiResponse.ofFailed("该技师暂停接单，请重新选择...");
        }
        // 查询项目信息
        Item item = itemMapper.selectById(dto.getItemId());
        /*if (item.getStock() < 1) {
            return ApiResponse.ofStatus(MyStatus.STOCK_NOT_ENOUGH);
        }*/
        executeTime.setTime(executeTime.getTime() + item.getTime() * 60 * 1000);
        LocalDateTime orderTime = LocalDateTime.ofInstant(executeTime.toInstant(), ZoneId.systemDefault());
        int count = leaveMapper.selectLeaveCountByOrderTime(orderTime, Long.valueOf(dto.getTechnicianId()));
        if (count > 0) {
            return ApiResponse.ofFailed("该技师已请假，暂不提供服务...");
        }

        // 判断该技师是否有订单
        Order serviceOrder = orderMapper.selectBusyCountByOrderTime(DateUtil.parseDateTime(dto.getExecuteTime()), dto.getTechnicianId());
        if (Objects.nonNull(serviceOrder)) {
            long start = serviceOrder.getExecuteTime().getTime();
            long end = System.currentTimeMillis();
            long min = (end - start) / (1000 * 60);
            return ApiResponse.ofFailed("该技师忙碌中，请稍后...,在" + min + "分钟后可提供服务");
        }

        Order order = new Order();
        BeanUtil.copyProperties(dto, order);
        //item.setStock(item.getStock() - 1);
        //itemMapper.updateById(item);
        order.setId(snowflake.nextIdStr());
        order.setItemContent(item.getContent());
        order.setItemImage(item.getImage());
        order.setItemPrice(item.getPrice());
        order.setItemTitle(item.getTitle());
        order.setItemType(item.getType().toString());
        order.setItemTime(item.getTime());
        order.setExecuteTime(DateUtil.parseDateTime(dto.getExecuteTime()));
        orderMapper.insert(order);
        Branch branch = branchService.getById(order.getBranchId());
        User user = userMapper.selectById(order.getUserId());
        WxClient.orderSubscribe(user.getOpenId(), item.getTitle(), Utils.format(new Date(), "yyyy-MM-dd HH:mm:ss"), branch.getTitle(), branch.getTel(), technician.getNickName(),order.getId());
        return ApiResponse.ofSuccess();
    }

    @ApiOperation("取消订单")
    @GetMapping("cancel-order/{orderId}/{fromId}")
    public ApiResponse cancelOrder(@PathVariable Long orderId, @PathVariable String fromId) {
        Order order = orderMapper.selectById(orderId);
        if (order.getOrderStatus().equals(OrderStatus.COMPLETED.getCode().toString())) {
            throw new BusinessException("订单已完成，不可取消");
        }
        order.setOrderStatus(OrderStatus.CANCELED.getCode().toString());

        //Item item = itemMapper.selectById(order.getItemId());
        //item.setStock(item.getStock() + 1);
        User user = userMapper.selectById(order.getUserId());

        //itemMapper.updateById(item);
        orderMapper.updateById(order);
        userMapper.updateById(user);

        Item item = itemMapper.selectById(order.getItemId());
        Branch branch = branchService.getById(order.getBranchId());
        // 发送消息
        WxClient.orderCancel(user.getOpenId(), item.getTitle(), Utils.format(order.getCreateTime(), "yyyy-MM-dd HH:mm:ss"), branch.getTitle(), "您取消了预约订单",order.getId());
        return ApiResponse.ofSuccess();
    }

    @ApiOperation(value = "订单列表", notes = "已完成 与 未开始 订单列表统一调用该接口")
    @PostMapping("order-list")
    public ApiResponse<List<Order>> orderList(@RequestBody OrderListDto dto) {
        PageInfo<Order> pageInfo = new PageInfo<>(dto.getPageCurr(), dto.getPageSize());
        List<Order> list = orderMapper.selectByPage(pageInfo, dto);
        pageInfo.setRecords(list);
        return ApiResponse.ofSuccess(pageInfo);
    }

    @ApiOperation("消费明细")
    @PostMapping("consume-list")
    public ApiResponse<List<Consume>> consumeList(@RequestBody ConsumeListDto dto) {
        PageInfo<Consume> pageInfo = new PageInfo<>(dto.getPageCurr(), dto.getPageSize());
        IPage<Consume> consumeIPage = consumeMapper.selectPage(pageInfo,
                new LambdaQueryWrapper<Consume>().eq(Consume::getUserId, dto.getUserId()).eq(Consume::getStatus,
                        StatusType.NORMAL.getCode()).orderByDesc(Consume::getCreateTime));
        List<Consume> consumes = consumeIPage.getRecords();
        Item item;
        for (Consume consume : consumes) {
            if (!consume.getItemId().equals(0L)) {
                item = itemMapper.selectById(consume.getItemId());
                consume.setItemName(item.getTitle());
                consume.setImage(item.getImage());
            }
        }
        consumeIPage.setRecords(consumes);
        return ApiResponse.ofSuccess(consumeIPage);
    }

    @ApiOperation("预约查看")
    @PostMapping("order-info")
    public ApiResponse<OrderInfoVo> orderInfo(@RequestBody @Validated OrderInfoDto dto) {
        OrderInfoVo vo = orderMapper.selectOrderInfoByOrderId(dto.getOrderId());
        if (vo.getBranchImg().split(",").length > 1) {
            vo.setBranchImg(vo.getBranchImg().split(",")[0]);
        }
        // 当前用户经纬度
        GlobalCoordinates source = new GlobalCoordinates(dto.getLat(), dto.getLng());
        // 当前门店经纬度
        GlobalCoordinates target = new GlobalCoordinates(vo.getLat(), vo.getLng());
        vo.setDistance(getDistanceMeter(source, target, Ellipsoid.Sphere));
        return ApiResponse.ofSuccess(vo);
    }

    private static double getDistanceMeter(GlobalCoordinates gpsFrom, GlobalCoordinates gpsTo, Ellipsoid
            ellipsoid) {

        // 创建GeodeticCalculator，调用计算方法，传入坐标系、经纬度用于计算距离
        GeodeticCurve geoCurve = new GeodeticCalculator().calculateGeodeticCurve(ellipsoid, gpsFrom, gpsTo);

        // 结果保留两位小数
        return (double) Math.round(geoCurve.getEllipsoidalDistance() * 100 / 1000) / 100;
    }

    @ApiOperation("员工评价")
    @PostMapping("staff-evaluate")
    public ApiResponse<StaffEvaluateVo> staffEvaluate(@RequestBody StaffEvaluateDto dto) {
        return ApiResponse.ofSuccess(evaluateService.staffEvaluate(dto));
    }

    @ApiOperation("员工风采")
    @PostMapping("staff-mien")
    public ApiResponse<List<StaffMienVo>> staffMien(@RequestBody StaffMienDto dto) {
        return ApiResponse.ofSuccess(branchService.staffMien(dto));
    }

    @ApiOperation("服务过用户的技师列表")
    @PostMapping("serviced-staff")
    public ApiResponse<PageInfo<StaffSimpleInfo>> servicedStaff(@RequestBody ServicedStaffDto dto) {
        return ApiResponse.ofSuccess(branchService.servicedStaff(dto));
    }

    @ApiOperation("员工列表")
    @PostMapping("staff-list")
    public ApiResponse<PageInfo<StaffSimpleInfo>> staffList(@RequestBody StaffListDto dto) {
        return ApiResponse.ofSuccess(branchService.staffList(dto));
    }

    @ApiOperation("修改手机号")
    @PostMapping("alter-phone-number")
    public ApiResponse alterPhoneNumber(@Validated @RequestBody AlterPhoneNumberDto dto) {
        User user = userMapper.selectById(dto.getUserId());
        user.setPhoneNumber(dto.getPhoneNumber());
        userMapper.updateById(user);
        return ApiResponse.ofSuccess();
    }


    @ApiOperation("用户查看自己的订单")
    @PostMapping("user-order-list")
    public ApiResponse<PageInfo<StaffOrderVo>> userOrder(@RequestBody UserOrderDto dto) {
        PageInfo<StaffOrderVo> pageInfo = new PageInfo<>(dto.getPageCurr(), dto.getPageSize());
        List<Order> userOrderList = orderMapper.selectUserOrder(pageInfo, dto.getUserId(), dto.getOrderStatus());
        log.info(">>>>>>>>>>>>>>>> {}", userOrderList);
        List<StaffOrderVo> vos = Lists.newArrayList();
        for (Order record : userOrderList) {
            User user = userMapper.selectById(record.getUserId());
            log.info(">>>>>>>>>>>>>>>user {}", user);
            StaffOrderVo vo = new StaffOrderVo();
            vo.setCustomerName(user.getNickName().charAt(0) + ("男".equals(user.getSex()) ? "先生" : "女士"));
            vo.setCustomerPhone(user.getPhoneNumber());
            vo.setOrderStatus(Integer.valueOf(record.getOrderStatus()));
            vo.setTechnicianAvatar(record.getTechnicianAvatar());
            vo.setTechnicianName(record.getTechnicianName());
            vo.setTechnicianPhone(record.getTechnicianPhone());
            vo.setItemTitle(record.getItemTitle());
            vo.setCustomerId(user.getId());
            SimpleDateFormat df = new SimpleDateFormat("yyyy.MM.dd HH:mm");
            String format = df.format(record.getExecuteTime());
            String week = DateUtils.calculateWeekDay(Integer.parseInt(format.split(" ")[0].split("\\.")[0]), Integer.parseInt(format.split(" ")[0].split("\\.")[1]), Integer.parseInt(format.split(" ")[0].split("\\.")[2]));
            String dayTime = DateUtils.dayTime(Integer.parseInt(format.split(" ")[1].split(":")[0]));
            vo.setDate(format.split(" ")[0]);
            vo.setTime(week + dayTime + format.split(" ")[1]);
            vo.setTitle(record.getBranchTitle());
            vos.add(vo);
        }
        pageInfo.setRecords(vos);
        return ApiResponse.ofSuccess(pageInfo);
    }

}
